﻿#include <string>
#include "track_seek.hh"

using namespace std;

int main(int argc, char **argv)
{
	if (argc == 1) {
    cout << cRED << "Parameter needed!" << cRESET << endl;
    show_info(argv[0]);
    return -1;
  }

	// -f
	string data_filename;
	// -o
	string save_filename_append = "track_seek";
	// -e
	double rmse_upper = 10; // unit mm
	// -N
	int cadidate_hit_num = 5;
	// -L
	int min_hit_layer = 3;
	// -D
	int total_layer_used = 4;
	// -r offset and rotate matrix
	string offset_filename;
	// -t
	long long timestamp_in = 0;
	// -j
	bool is_save_json = false;
	// -l
	string mask_layer_used = "FF";
	// -O
	int calc_target_layer = 0;
	// -F
	bool is_first = false;
	bool is_calc_target_layer = false;
  // -i
  int acq_interval = 5;
  // -I
  int device_id = 1;

	cout << "Begin process" << endl;
	int c = 0;
  std::string dir_name = ".";
	while ((c = getopt(argc, argv, "A:f:o:e:N:L:D:r:t:jl:TO:F:i:I:")) != EOF)
    {
      switch (c)
        {
        case 'A':
          dir_name = optarg;
          break;
        case 'f':
          data_filename = optarg;
          break;
        case 'o':
          save_filename_append = optarg;
          break;
        case 'e':
          rmse_upper = atof(optarg);
          break;
        case 'N':
          cadidate_hit_num = atoi(optarg);
          break;
        case 'L':
          min_hit_layer = atoi(optarg);
          break;
        case 'D':
          total_layer_used = atoi(optarg);
          break;
        case 'r':
          offset_filename = optarg;
          break;
        case 't':
          timestamp_in = atoll(optarg);
          break;
        case 'j':
          is_save_json = true;
          break;
        case 'l':
          mask_layer_used = optarg;
          break;
        case 'O':
          calc_target_layer = atoi(optarg);
          is_calc_target_layer = true;
          break;
        case 'F':
          is_first = true;
          break;
        case 'i':
          acq_interval = atoi(optarg);
          break;
        case 'I':
          device_id = atoi(optarg);
          break;
        case '?':
          cout << "<<----------\?\?---------->>" << endl;
          cout << cRED << "unknow parameters " << argv[optind] << " " << optarg << cRESET << endl;
          cout << "<<----------\?\?---------->>" << endl;
          cout << "Or forget break in the last case???" << endl;
          show_info(argv[0]);
          return -1;
          break;
        default:
          cout << cRED << "Some option is not include in the switch. Please check the main()" << cRESET << endl;
          show_info(argv[0]);
          break;
        }
    }
	// 转换为自1970年1月1日以来的毫秒数
  auto now = std::chrono::system_clock::now();
  auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
  // 获取13位的Unix时间戳
  long long timestamp = duration.count();
  if (timestamp_in != 0) {
    timestamp = timestamp_in;
  }
	else {
    cout << "No time stamp input. Use current time instead" << endl;
  }

  //
	if (data_filename.empty()) {
      cout << cRED << " -f parameter is needed" << cRESET << endl;
      show_info(argv[0]);
  }
	vector<string> filename_suffix = split_string(data_filename, ".root");
	if (filename_suffix.size() != 2) {
    cout << cRED << "File name ERROR: " << data_filename << cRESET << endl;
    return -1;
  }
	vector<string> filename_suffix2 = split_string(data_filename, "/");
	string save_filename = filename_suffix[1] + "_" + save_filename_append + "_rmse" + to_string((int)rmse_upper) + "mm_" + to_string(cadidate_hit_num) + "hits_" + to_string(min_hit_layer) + "minlayer_" + mask_layer_used;

  // track finder
	best_tracker track_finder(data_filename, save_filename, total_layer_used);

  // fitting criteria
  track_finder.set_max_rmse(rmse_upper);
  track_finder.set_max_hitnum(cadidate_hit_num);
  track_finder.set_min_layer(min_hit_layer);

  // layer mask
  int user_set_layer_used_int = 0;
  stringstream ss;
  ss << hex << mask_layer_used;
  ss >> user_set_layer_used_int;
  track_finder.set_layer_used(user_set_layer_used_int);

  if (!offset_filename.empty()) {
    track_finder.load_alignment(offset_filename);
  }

  if (is_calc_target_layer) {
    track_finder.set_target_layer_calc(calc_target_layer, is_first);
  }

  // json
	if (is_save_json) {
    string json_file_path = dir_name + "/" + std::to_string(timestamp) + "/";

    // Check the save path is exist or not if not create
    if (stat(json_file_path.c_str(), &info) != 0) {
      cout << cYELLOW << "Path " << json_file_path
           << " does not exist and create one" << endl
           << cRESET;
      fs::create_directory(json_file_path);
    }
    else if (info.st_mode & S_IFDIR) {
      cout << cGREEN << "Save file at " << json_file_path << cRESET << endl;
    }
    else {
      cout << cYELLOW << "Path " << json_file_path << " does not exist and create one" << endl
           << cRESET;
      fs::create_directory(json_file_path);
    }
    fs::create_directory(json_file_path + "status/");
    fs::create_directory(json_file_path + "event/");
    track_finder.acq_interval = acq_interval;
    track_finder.device_id = device_id;
    track_finder.json_file_path = json_file_path;
    track_finder.is_save_json = true;
  }

	// Time start
	cout << "Start to run" << endl;
	cout << "File name: " << data_filename << endl;
	cout << "Save file name: " << save_filename << endl;
	cout << "RMSE upper limit: " << rmse_upper << " mm" << endl;
	cout << "Candidate hit number (max) per layer: " << cadidate_hit_num << endl;
	cout << "Minimum layer nr for fitting: " << min_hit_layer << endl;
	cout << "Total Nr of layer used: " << total_layer_used << endl;
	cout << "Hex masks of the layer used: " << mask_layer_used << endl;
	cout << "Alignment file name: " << offset_filename << endl;
	cout << "Timestamp: " << timestamp << endl;

  // finder running
	auto start = std::chrono::system_clock::now();
	auto start_time = std::chrono::system_clock::to_time_t(start);
	cout << "Start time: " << std::ctime(&start_time) << endl;

	if (!track_finder.run()) {
    cout << cRED << "Run ERROR" << cRESET << endl;
    return -1;
  }

	auto end = std::chrono::system_clock::now();
	auto end_time = std::chrono::system_clock::to_time_t(end);
	cout << "End time: " << std::ctime(&end_time) << endl;
	cout << "Time cost: " << std::chrono::duration_cast<std::chrono::seconds>(end - start).count() << "s" << endl;
}

void show_info(char *name)
{
	for (int i = 0; i < 30; i++)
		cout << "-";
	cout << endl;

  cout << cGREEN << "Usage: " << name << " -[parameter]" << endl
       << cBLUE << "Parameter lists:" << cGREEN << endl
       << "    -f [Filename] (required)" << endl
       << "    -e [Upper limit of the RMSE (Unit mm, default: 10mm)] " << endl
       << "    -N [Maximum possible hit strip number, default 3]" << endl
       << "    -l [layer used] (option)" << endl
       << "    -L [Min hit layer, default 3]" << endl
       << "    -D [Detetor number used (Default: 4)]" << endl
       << "    -r [Alignment filename] (option)"
       << "    -t [Start timestamp for json export] (option)" << endl
       << "    -O [Target layer to calculate] (option)" << endl
       << "    -F [Is choose first hit to calculate offset] (option)"
       << endl

       << cRESET << endl;
}

vector<string> split_string(const string &str, string delims, int inc)
{
	std::vector<std::string> result;
	size_t i = str.rfind(delims, str.length());
	if (i == str.length() - 1 || i == string::npos)
    {
      result.push_back(str);
    }
	else
    {
      result.push_back(str.substr(i + inc, str.length() - i));
      result.push_back(str.substr(0, i));
    }
	return result;
}
